/**
 *
 */
package com.honeybees.framework.common.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import org.bouncycastle.crypto.BlockCipher;
import org.bouncycastle.crypto.BufferedBlockCipher;
import org.bouncycastle.crypto.DataLengthException;
import org.bouncycastle.crypto.InvalidCipherTextException;
import org.bouncycastle.crypto.engines.RijndaelEngine;
import org.bouncycastle.crypto.modes.CBCBlockCipher;
import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher;
import org.bouncycastle.crypto.paddings.ZeroBytePadding;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.util.encoders.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StreamUtils;

/**
 * <dl>
 * <dt><b> AES（Rijndael）加密 </b></dt>
 * <p>
 * <dd>加密密钥必须是 16/20/24/28/32 位。</dd>
 * <p>
 * <dd>密钥32位，明文少于32位时，加密结果为44位。</dd>
 * </dl>
 * <p>
 * Copyright (c) All rights reserved.
 * </p>
 *
 * @author 李远明
 * @see org.bouncycastle.crypto.engines.RijndaelEngine#generateWorkingKey(byte[])
 * @see org.bouncycastle.util.encoders.Base64
 * @see org.bouncycastle.util.encoders.Hex
 * @since 2015-11-15 18:43:57 新建
 */
public final class AESUtil {

    private static final Logger LOGGER = LoggerFactory.getLogger(AESUtil.class);

    /**
     * 密钥
     */
    private static final String KEY = "bfa6026a858e4d3eb9192856ee624590";

    private static byte[] toKey(String key) {
        byte[] seed = key.getBytes();
        return seed;
    }

    /**
     * <dl>
     * <dt><b> 加密 </b></dt>
     * <p>
     * <dd></dd>
     * </dl>
     *
     * @param plainText 明文
     * @param key       密钥
     * @return 加密结果（使用Base64编码）
     * @author 李远明
     * @version 2015-11-15 18:48:49
     */
    public static String encrypt(String plainText, String key) {
        if (plainText == null || plainText.length() == 0) {
            throw new IllegalArgumentException("明文 plainText 不能为空");
        }
        if (key == null || key.length() == 0) {
            throw new IllegalArgumentException("明文 key 不能为空");
        }

        BlockCipher engine = new RijndaelEngine(256);
        BufferedBlockCipher cipher = new PaddedBufferedBlockCipher(new CBCBlockCipher(engine), new ZeroBytePadding());

        byte[] seed = toKey(key); // 密钥
        cipher.init(true, new KeyParameter(seed));

        byte[] plainBytes = plainText.getBytes(); // 密码明文
        byte[] cipherBytes = new byte[cipher.getOutputSize(plainBytes.length)]; // 密码密文

        int cipherLength = cipher.processBytes(plainBytes, 0, plainBytes.length, cipherBytes, 0);
        try {
            cipher.doFinal(cipherBytes, cipherLength);
        } catch (DataLengthException e) {
            LOGGER.error("encrypt error", e);
        } catch (IllegalStateException e) {
            LOGGER.error("encrypt error", e);
        } catch (InvalidCipherTextException e) {
            LOGGER.error("encrypt error", e);
        }

        String result = new String(Base64.encode(cipherBytes));
        // System.out.println("encrypt: " + result);
        return result;
    }

    /**
     * <dl>
     * <dt><b> 解密 </b></dt>
     * <p>
     * <dd></dd>
     * </dl>
     *
     * @param cipherText 密文（使用Base64编码）
     * @param key        密钥
     * @return 明文
     * @author 李远明
     * @version 2015-11-15 19:00:53
     */
    public static String decrypt(String cipherText, String key) {
        if (cipherText == null || cipherText.length() == 0) {
            throw new IllegalArgumentException("密文 cipherText 不能为空");
        }
        if (key == null || key.length() == 0) {
            throw new IllegalArgumentException("明文 key 不能为空");
        }

        BlockCipher engine = new RijndaelEngine(256);
        BufferedBlockCipher cipher = new PaddedBufferedBlockCipher(new CBCBlockCipher(engine), new ZeroBytePadding());

        byte[] seed = toKey(key); // 密钥
        cipher.init(false, new KeyParameter(seed));

        byte[] cipherBytes = Base64.decode(cipherText.getBytes()); // 密码密文
        byte[] plainBytes = new byte[cipher.getOutputSize(cipherBytes.length)]; // 密码明文

        int cipherLength = cipher.processBytes(cipherBytes, 0, cipherBytes.length, plainBytes, 0);
        int outputLength = 0;
        try {
            outputLength = cipher.doFinal(plainBytes, cipherLength);
        } catch (DataLengthException e) {
            LOGGER.error("decrypt error", e);
        } catch (IllegalStateException e) {
            LOGGER.error("decrypt error", e);
        } catch (InvalidCipherTextException e) {
            LOGGER.error("decrypt error", e);
        }
        outputLength += cipherLength;

        // byte[] resultBytes = plainBytes;
        byte[] resultBytes = new byte[0];
        if (outputLength != cipherBytes.length) {
            resultBytes = new byte[outputLength];
            System.arraycopy(plainBytes, 0, resultBytes, 0, outputLength);
        }

        String result = new String(resultBytes);
        // System.out.println("decrypt: " + result);
        return result;
    }

    /**
     * <dl>
     * <dt><b> 加密 </b></dt>
     * <p>
     * <dd></dd>
     * </dl>
     *
     * @param plainText 明文
     * @return 加密结果（使用Base64编码）
     * @author 李远明
     * @version 2015-11-15 22:11:10
     */
    public static String encrypt(String plainText) {
        return encrypt(plainText, KEY);
    }

    /**
     * <dl>
     * <dt><b> 解密 </b></dt>
     * <p>
     * <dd></dd>
     * </dl>
     *
     * @param cipherText 密文（使用Base64编码）
     * @return 明文
     * @author 李远明
     * @version 2015-11-15 22:12:34
     */
    public static String decrypt(String cipherText) {
        return decrypt(cipherText, KEY);
    }

    public static void main(String[] args) {
        // String password = "888888"; // 密码
        // String encrypt = encrypt(password, KEY);
        // System.out.println(encrypt);
        // String decrypt = decrypt(encrypt, KEY);
        // System.out.println(decrypt);

        testFileEncryption();
    }

    static void testFileEncryption() {
        InputStream in = null;
        try {
            in = new FileInputStream(new File("D:\\TDDOWNLOAD\\00001.vcf"));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        byte[] data = null;
        try {
            data = StreamUtils.copyToByteArray(in);
        } catch (IOException e) {
            e.printStackTrace();
        }
        BlockCipher engine = new RijndaelEngine(256);
        BufferedBlockCipher cipher = new PaddedBufferedBlockCipher(new CBCBlockCipher(engine), new ZeroBytePadding());

        byte[] seed = toKey(KEY); // 密钥
        cipher.init(true, new KeyParameter(seed));

        byte[] plainBytes = data; // 密码明文
        byte[] cipherBytes = new byte[cipher.getOutputSize(plainBytes.length)]; // 密码密文

        int cipherLength = cipher.processBytes(plainBytes, 0, plainBytes.length, cipherBytes, 0);
        try {
            cipher.doFinal(cipherBytes, cipherLength);
        } catch (DataLengthException e) {
            LOGGER.error("encrypt error", e);
        } catch (IllegalStateException e) {
            LOGGER.error("encrypt error", e);
        } catch (InvalidCipherTextException e) {
            LOGGER.error("encrypt error", e);
        }

        OutputStream out = null;
        try {
            out = new FileOutputStream(new File("D:\\TDDOWNLOAD\\00001.vcf.0"));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        try {
            StreamUtils.copy(cipherBytes, out);
        } catch (IOException e) {
            e.printStackTrace();
        }

        String result = new String(Base64.encode(cipherBytes));
        System.out.println(result);
    }

}
